﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ActionPluginAPI;
using NAudio.Wave;
using System.IO;
using iMapa.Helper;
using System.Xml.Serialization;
using System.Net;
using System.Windows; 


namespace PlaySoundActionPlugin
{
    public class PlaySoundActionParameters : ViewModelBase,IActionParameters
    {
        private string id;

        public enum SourceSelector { opt0, opt1, opt2, opt3 }
        private SourceSelector selectedSource = SourceSelector.opt1;
        private string pathToFile;
        private int selectedDevice=0;
        private WaveFileWriter writer;

        private string ttsText;
        private List<String> langs= new List<String>();
        private String selectedLang="en";
        private bool recording = false;

        private List<WaveInCapabilities> deviceList;
        private WaveIn waveIn;
        private SampleAggregator sampleAggregator = new SampleAggregator();
        private float lastPeak;
        private long maxFileLength;

        [XmlIgnoreAttribute()]
        public string RootPath;
        
        public PlaySoundActionParameters()
        {
            this.id = this.GetHashCode().ToString();
            initLangs();
            sampleAggregator.MaximumCalculated += recorder_MaximumCalculated;
        }

        public PlaySoundActionParameters(string rootPath)
        {
            this.RootPath = rootPath;
            this.id = this.GetHashCode().ToString();
            initLangs();
            sampleAggregator.MaximumCalculated += recorder_MaximumCalculated;
        }

         [XmlIgnoreAttribute()]
        public string SoundFile
        {
            get
            {
                switch (selectedSource)
                {
                    case SourceSelector.opt0: return null;
                    case SourceSelector.opt1: return PathToFile;
                    case SourceSelector.opt2: return RootPath + this.id + ".wav";
                    case SourceSelector.opt3: return RootPath + this.id + ".mp3";
                }
                return null;
            }
            
        }

        [XmlIgnoreAttribute()]
        public List<WaveInCapabilities> DeviceList
        {
            get {
                if (deviceList == null)
                {
                    deviceList = new List<WaveInCapabilities>();
                    for (int i = 0; i < WaveIn.DeviceCount; i++)
                    {
                        WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(i);
                        deviceList.Add(deviceInfo);
                    }
                }
                return deviceList; }
            
        }

        [XmlIgnoreAttribute()]
        public int SelectedDevice
        {
            get { return selectedDevice; }
            set { selectedDevice = value; }
        }

        [XmlIgnoreAttribute()]
        public string PathToFile
        {
            get
            {
                if (pathToFile!=null && !pathToFile.Contains("\\"))
                {
                    return RootPath + pathToFile;
                }
                else
                {
                    return pathToFile;
                }
            }
            set
            {
                pathToFile = value;
                onPropertyChanged("PathToFile");
            }
        }

        [XmlIgnoreAttribute()]
        public SourceSelector SelectedSource
        {
            get { return selectedSource; }
            set
            {
                if (value != SourceSelector.opt0) 
                selectedSource = value;
                onPropertyChanged("SelectedSource");
            }
        }
        
        [XmlAttributeAttribute()]
        public String Filename
        {
            get { return SoundFile==null?null: new FileInfo(SoundFile).Name; }
            set
            {
                pathToFile = value;
            }
        }

        public void StartRecordig()
        {
            waveIn = new WaveIn();
            waveIn.DeviceNumber = selectedDevice;
            waveIn.DataAvailable += waveIn_DataAvailable;
            int sampleRate = 8000; // 8 kHz
            int channels = 1; // mono
            waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
            maxFileLength = waveIn.WaveFormat.AverageBytesPerSecond * 7;
            waveIn.StartRecording();
        }

        public void StopRecording()
        {
            if (waveIn != null)
            {
                waveIn.StopRecording();
                waveIn.Dispose();
                waveIn = null;
            }
        }
        
        [XmlIgnoreAttribute()]
        public bool Recording
        {
            get { return recording; }
            set { recording = value;
            onPropertyChanged("Recording");
            }
        }
        
        [XmlIgnoreAttribute()]
        public WaveFileWriter Writer
        {
            get { return writer; }
            set { writer = value; }
        }


        public void PersistToFile(string filename)
        {
            PlaySoundActionPlugin.Close();
            ObjectXMLSerializer<PlaySoundActionParameters>.Save(this, filename);
            try
            {
                if (PathToFile!=null && !PathToFile.Contains(RootPath) && Filename!=null)
                {
                    File.Copy(PathToFile, RootPath + Filename);
                }
            }
            catch (Exception e) { }
        }

        void waveIn_DataAvailable(object sender, WaveInEventArgs e)
        {
            if (Recording && writer!=null)
            {
                int toWrite = (int)Math.Min(maxFileLength - writer.Length, e.BytesRecorded);
                if (toWrite > 0)
                    writer.WriteData(e.Buffer, 0, e.BytesRecorded);
                else
                {
                    Recording = false;
                    writer.Flush();
                    writer.Close();
                }
            }
            for (int index = 0; index < e.BytesRecorded; index += 2)
            {
                short sample = (short)((e.Buffer[index + 1] << 8) |
                                        e.Buffer[index + 0]);
                float sample32 = sample / 32768f;
                sampleAggregator.Add(sample32);
            }
        }
        void recorder_MaximumCalculated(object sender, MaxSampleEventArgs e)
        {
            lastPeak = Math.Max(e.MaxSample, Math.Abs(e.MinSample));
            onPropertyChanged("CurrentInputLevel");
        }

        // multiply by 100 because the Progress bar's default maximum value is 100 
        public float CurrentInputLevel { get { return lastPeak * 100; } }

        [XmlIgnoreAttribute()]
        public SampleAggregator SampleAggregator
        {
            get { return sampleAggregator; }
            set { sampleAggregator = value; }
        }

        internal void InitWriter()
        {
            PlaySoundActionPlugin.Close();
            if (writer != null)
            {
                sampleAggregator.RaiseRestart();
                string name= writer.Filename;
                writer.Close();
                writer.Dispose();
                File.Delete(name);
            }
            writer = new WaveFileWriter(RootPath + this.id +".wav", waveIn.WaveFormat);
        }


        public void SetID(string value)
        {
            this.id = value;
        }

        public string GetID()
        {
            return id;
        }


        public string[] GetResourceFiles()
        {
            PlaySoundActionPlugin.Close();
            return File.Exists(SoundFile) ? new string[] { SoundFile }:null ;
        }

        public void LoadGoogleTTS(String text, String lang)
        {
            lang = lang == null ? "en" : lang;
            WebRequest request = WebRequest.Create(string.Format("http://translate.google.com/translate_tts?ie=UTF-8&tl={1}&q={0}", Uri.EscapeUriString(text), Uri.EscapeUriString(lang)));
            request.Method = "GET";
            request.Timeout = 5000;

            try
            {
                WebResponse response = request.GetResponse();

                if (response != null && response.ContentType.Contains("audio"))
                {
                    Stream stream = response.GetResponseStream();
                    PlaySoundActionPlugin.Close();
                    FileStream localStream = new FileStream(RootPath + this.id + ".mp3", FileMode.OpenOrCreate);
                    stream.CopyTo(localStream);
                    
                    stream.Close();
                    localStream.Flush();
                    localStream.Close();
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void initLangs()
        {
            langs.Add("en"); langs.Add("cs"); langs.Add("de"); langs.Add("fr"); langs.Add("hu"); langs.Add("it"); langs.Add("es");
        }

        [XmlIgnoreAttribute()]
        public string TtsText
        {
            get { return ttsText; }
            set { ttsText = value;
            onPropertyChanged("TtsText");
            }
        }
        [XmlIgnoreAttribute()]
        public List<String> Langs
        {
            get { return langs; }
            set { langs = value; }
        }
        [XmlIgnoreAttribute()]
        public String SelectedLang
        {
            get { return selectedLang; }
            set { selectedLang = value; }
        }
        
    }
}
